package Server_Netty.TCP;

import Server_Netty.DataCallBackClass;
import Server_Netty.Main_Send_Receive_Manager;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.LinkedBlockingQueue;


public class TCPServer {
    public static final Logger LOGGER = LoggerFactory.getLogger(TCPServer.class);
    //存放接收数据的队列
    public LinkedBlockingQueue<DataCallBackClass> ReceiveDataQueue = new LinkedBlockingQueue<DataCallBackClass>();

    public int TCP_RoleId;  //tcp通道的通道号
    public TCPServer(int RoleId) {
        TCP_RoleId=RoleId;
    }
    public int getTCP_RoleId() {
        return TCP_RoleId;
    }

    public boolean bind(String local_address, int local_port) throws Exception{
        boolean b_start_success = false;

        //配置NIO线程组
        EventLoopGroup boosGroup = new NioEventLoopGroup(1);
        EventLoopGroup workerGroup = new NioEventLoopGroup(1);

        try{
            //服务端辅助启动类配置
            ServerBootstrap bootstrap = new ServerBootstrap();
            //设置两个线程组boosGroup和workerGroup
            bootstrap.group(boosGroup,workerGroup)
                    //设置服务端通道实现类型
                    .channel(NioServerSocketChannel.class)
                    //设置线程队列得到连接个数
                    //系统用于临时存放已完成三次握手的请求的队列的最大长度
                    .option(ChannelOption.SO_BACKLOG,100)
                    //设置保持活动连接状态
                    .childOption(ChannelOption.SO_KEEPALIVE,true)
                    //初始化通道类对象
                    .childHandler(new ChildChannelHandler())
                    //设置发送缓冲区和接收缓冲区的大小
                    .childOption(ChannelOption.SO_SNDBUF,1024 * 1024 * 8)
                    .childOption(ChannelOption.SO_RCVBUF,1024 * 1024 * 8)
                    //设置接收Buffer的分配器
                    .childOption(ChannelOption.RCVBUF_ALLOCATOR,new AdaptiveRecvByteBufAllocator(64,15000,65536));
            LOGGER.info("port:"+local_port+"[TCP服务端启动了]");
            //绑定端口、启动服务器
            ChannelFuture channelFuture = bootstrap.bind(local_address,local_port).sync();
            b_start_success = true;
            //对关闭通道进行监听
            channelFuture.channel().closeFuture().sync();
        }
        finally {
            //优雅地释放线程资源
            LOGGER.info("port:"+local_port+"[TCP服务端关闭了]");
            boosGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
        return b_start_success;
    }

    /**
     * 网络事件处理器
     * */
    private class ChildChannelHandler extends ChannelInitializer<SocketChannel> {
        @Override
        protected void initChannel(SocketChannel socketChannel) throws Exception {
            //添加自定义协议的编解码工具(主要用于TCP的粘拆包) -- 用两个字节表示TCP数据包内容的长度
            socketChannel.pipeline().addLast(new TCPBytesDataProtocolEncoder());
            socketChannel.pipeline().addLast(new TCPBytesDataProtocolDecoder());

            //处理网络IO
            socketChannel.pipeline().addLast(new TCPServerHandler());
        }
    }

    private int Test_Count=0;

    public class TCPServerHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            TCPBytesDataProtocol data = (TCPBytesDataProtocol) msg;
            DataCallBackClass UndealData = new DataCallBackClass(TCP_RoleId,data.get_real_DataLength(),data.getContent());

            if(ReceiveDataQueue.size() <= 50000) { //队列长度未溢出,数据存入队列
                if(Test_Count >= 32766) {
                    LOGGER.info("TCP_RoleId:"+TCP_RoleId+"数据包又接收32767个");
                    Test_Count = 0;
                }
                else {
                    Test_Count++;
                }
            }
            ReceiveDataQueue.offer(UndealData);
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            LOGGER.error("TCP_RoleId:"+TCP_RoleId+"exceptionCaught出现异常，错误码："+cause.getCause());
            cause.printStackTrace();

            Channel channel = ctx.channel();
            if(channel.isActive()) {
                ctx.close();
            }
        }

        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            LOGGER.info("TCP_RoleId:"+TCP_RoleId+"客户端已连接");

            if (Main_Send_Receive_Manager.RoleID_map.get(TCP_RoleId) != null && Main_Send_Receive_Manager.RoleID_map.get(TCP_RoleId).equals(ctx)) {
                LOGGER.info("TCP_RoleId:"+TCP_RoleId+"的map映射已存在");
            } else {
                Main_Send_Receive_Manager.RoleID_map.put(TCP_RoleId, ctx);
                LOGGER.info(TCP_RoleId+":TCP_map.put(TCP_RoleId, ctx),即将TCP的角色号加入map映射");
            }

            if(Main_Send_Receive_Manager.RoleID_ReceiveQueue.get(TCP_RoleId)==null){
                Main_Send_Receive_Manager.RoleID_ReceiveQueue.put(TCP_RoleId,ReceiveDataQueue);
            }
        }

        @Override
        public void channelInactive(ChannelHandlerContext ctx) throws Exception {
            LOGGER.info("TCP_RoleId:"+TCP_RoleId+"客户端已断开");
            removeChannnelMap();
            LOGGER.info("TCP_RoleId:"+TCP_RoleId+"的map映射已删除");
            super.channelInactive(ctx);
        }

        /**
         * 删除map中的ChannelHandlerContext
         * */
        private void removeChannnelMap() {
            if (Main_Send_Receive_Manager.RoleID_map.get(TCP_RoleId) != null) {
                Main_Send_Receive_Manager.RoleID_map.remove(TCP_RoleId);
            }
        }
    }
}
